package service

import (
	"context"
	"fmt"
	"fx_swift_ifcgate_agent/api"
	"fx_swift_ifcgate_agent/internal/model"
	"fx_swift_ifcgate_agent/pkg/code"
	"fx_swift_ifcgate_agent/pkg/global"
	"fx_swift_ifcgate_agent/pkg/internalerrors"
	"fx_swift_ifcgate_agent/pkg/logger"
	"fx_swift_ifcgate_agent/pkg/utils"
	"github.com/gogf/gf/v2/container/gmap"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/golang-module/carbon/v2"
	"github.com/spf13/cast"
)

type IIndexSrv interface {
	// 收款趋势
	CollectTrends(ctx context.Context, req *api.CollectTrendsReq) ([]*api.CollectTrendsRes, error)

	// 付款趋势
	PayTrends(ctx context.Context, req *api.PayTrendsReq) (*api.PayTrendsRes, error)

	// 商户账户总金额
	MerchantAccount(ctx context.Context) (*api.MerchantAccountRes, error)

	// 交易总金额
	TotalTransactionAmount(ctx context.Context) (*api.TotalTransactionAmountRes, error)

	// 分佣金额
	TotalCommission(ctx context.Context) (*api.TotalCommissionRes, error)

	//获取公告
	GetPlacard(ctx context.Context) ([]*api.GetPlacardRes, error)
}
type indexSrv struct {
}

func NewIndexSrv() IIndexSrv {
	return &indexSrv{}
}

// 收款趋势
func (i *indexSrv) CollectTrends(ctx context.Context, req *api.CollectTrendsReq) ([]*api.CollectTrendsRes, error) {
	type DbVo struct {
		Amount      float64 `json:"amount"`
		Nums        int     `json:"nums"`
		ApproveTime string  `json:"approve_time"`
	}
	type TempObj struct {
		Amount float64 `json:"amount"`
		Nums   int     `json:"nums"`
	}
	var (
		account  string
		year     string
		err      error
		dbVoList []DbVo
		result   []*api.CollectTrendsRes
	)

	account = ctx.Value("Account").(string)

	if len(req.Year) == 0 {
		year = cast.ToString(carbon.Now().Year())
	} else {
		year = req.Year
	}
	mod := global.GFDB.Schema("fx").Model("fx.ifcgate_trade_order_mapping_flow")
	mod.Fields("SUM(amount) amount,count(1) nums,date_format(approve_time,'%Y-%m') approve_time")
	if len(req.Currency) > 0 {
		mod.Where("currency=?", req.Currency)
	}
	if err = mod.Where("status='02' and date_format(approve_time,'%Y') = ? and account = ?", year, account).
		Group("approve_time").
		Order("approve_time desc").Scan(&dbVoList); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(dbVoList) > 0 {
		maps := gmap.ListMap{}
		for _, value := range dbVoList {
			if !maps.Contains(value.ApproveTime) {
				maps.Set(value.ApproveTime, TempObj{
					Amount: value.Amount,
					Nums:   value.Nums,
				})
			} else {
				valueObj := maps.Get(value.ApproveTime).(TempObj)
				valueObj.Nums += value.Nums
				valueObj.Amount += value.Amount
				maps.Set(value.ApproveTime, valueObj)
			}
		}

		for _, dateStr := range utils.GenerateYearList(year) {
			if !maps.Contains(dateStr) {
				maps.Set(dateStr, TempObj{
					Amount: 0.0,
					Nums:   0,
				})
			}
		}

		maps.Iterator(func(key interface{}, value interface{}) bool {
			result = append(result, &api.CollectTrendsRes{
				Amount:      cast.ToString(value.(TempObj).Amount),
				Nums:        cast.ToString(value.(TempObj).Nums),
				ApproveTime: key.(string),
			})
			return true
		})
	}
	return result, err
}

// 付款趋势
func (i *indexSrv) PayTrends(ctx context.Context, req *api.PayTrendsReq) (*api.PayTrendsRes, error) {
	type DbVo struct {
		Amount    float64 `json:"amount"`
		Nums      int     `json:"nums"`
		CreatedAt string  `json:"created_at"`
	}
	var (
		account           string
		err               error
		year              string
		domesticVoList    []DbVo
		internationVoList []DbVo
		result            = &api.PayTrendsRes{}
		domesticList      []*api.DomesticTrendsList
		internationList   []*api.InternationTrendsList
	)

	account = ctx.Value("Account").(string)

	if len(req.Year) == 0 {
		year = cast.ToString(carbon.Now().Year())
	} else {
		year = req.Year
	}
	mod := global.GFDB.Schema("fx").Model("fx.ifcgate_domestic_transfer_record")
	mod.Fields("SUM(debit_amount) amount,count(1) nums,date_format(created_at,'%Y-%m') created_at")
	if len(req.Currency) > 0 {
		mod.Where("debit_currency=?", req.Currency)
	}
	if err = mod.Where("date_format(created_at,'%Y') = ? and account = ?", year, account).
		Group("created_at").
		Order("created_at desc").Scan(&domesticVoList); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}

	mod1 := global.GFDB.Schema("fx").Model("fx.ifcgate_internation_transfer_record")
	mod1.Fields("SUM(debit_amount) amount,count(1) nums,date_format(created_at,'%Y-%m') created_at")
	if len(req.Currency) > 0 {
		mod1.Where("debit_currency=?", req.Currency)
	}
	if err = mod1.Where("date_format(created_at,'%Y') = ? and account = ?", year, account).
		Group("created_at").
		Order("created_at desc").Scan(&internationVoList); err != nil {
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	if len(domesticVoList) > 0 {
		type TempObj struct {
			Amount float64 `json:"amount"`
			Nums   int     `json:"nums"`
		}
		maps := gmap.ListMap{}
		for _, value := range domesticVoList {
			if !maps.Contains(value.CreatedAt) {
				maps.Set(value.CreatedAt, TempObj{
					Amount: value.Amount,
					Nums:   value.Nums,
				})
			} else {
				valueObj := maps.Get(value.CreatedAt).(TempObj)
				valueObj.Nums += value.Nums
				valueObj.Amount += value.Amount
				maps.Set(value.CreatedAt, valueObj)
			}
		}

		for _, dateStr := range utils.GenerateYearList(year) {
			if !maps.Contains(dateStr) {
				maps.Set(dateStr, TempObj{
					Amount: 0.0,
					Nums:   0,
				})
			}
		}

		maps.Iterator(func(key interface{}, value interface{}) bool {
			domesticList = append(domesticList, &api.DomesticTrendsList{
				Amount:    cast.ToString(value.(TempObj).Amount),
				Nums:      cast.ToString(value.(TempObj).Nums),
				CreatedAt: key.(string),
			})
			return true
		})
		result.DomesticTrendsList = domesticList
	}
	if len(internationVoList) > 0 {
		type TempObj struct {
			Amount float64 `json:"amount"`
			Nums   int     `json:"nums"`
		}
		maps := gmap.ListMap{}
		for _, value := range internationVoList {
			if !maps.Contains(value.CreatedAt) {
				maps.Set(value.CreatedAt, TempObj{
					Amount: value.Amount,
					Nums:   value.Nums,
				})
			} else {
				valueObj := maps.Get(value.CreatedAt).(TempObj)
				valueObj.Nums += value.Nums
				valueObj.Amount += value.Amount
				maps.Set(value.CreatedAt, valueObj)
			}
		}

		for _, dateStr := range utils.GenerateYearList(year) {
			if !maps.Contains(dateStr) {
				maps.Set(dateStr, TempObj{
					Amount: 0.0,
					Nums:   0,
				})
			}
		}

		maps.Iterator(func(key interface{}, value interface{}) bool {
			internationList = append(internationList, &api.InternationTrendsList{
				Amount:    cast.ToString(value.(TempObj).Amount),
				Nums:      cast.ToString(value.(TempObj).Nums),
				CreatedAt: key.(string),
			})
			return true
		})
		result.InternationTrendsList = internationList
	}
	return result, err
}

// 商户账户总金额
func (i *indexSrv) MerchantAccount(ctx context.Context) (*api.MerchantAccountRes, error) {
	var (
		err             error
		account         string
		merchantToken   string
		companyUserList []*model.IfcgateCompanyUser
		finalAmount     float64
		resultAmount    map[string]float64
		rateObjList     []*model.IfcgateRate
		currencyMap     = make(map[string]float64)
		tList           = make([]map[string]float64, 0)
	)
	account = ctx.Value("Account").(string)

	// 查询代理商下所有的商户号
	if err = global.GFDB.Model("ifcgate_company_user").
		Where("agent_account=? and merchant_no <> ''", account).Scan(&companyUserList); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}

	if err = global.GFDB.Schema("fx").Model("ifcgate_rate").
		Scan(&rateObjList); err != nil {
		logger.SugarLogger.Error(err)
		return nil, err
	}

	for _, value := range rateObjList {
		currencyMap[value.Currency] = value.Rate
	}

	for _, value := range companyUserList {
		merchantToken, err = GetMerchantToToken(ctx, value.MerchantNo)
		if merchantToken == "" || err != nil {
			logger.SugarLogger.Error(err)
			return nil, internalerrors.New(code.ErrUnknown, err.Error())
		}
		resultAmount, err = AccountsCurrencyToUSD(merchantToken)
		tList = append(tList, resultAmount)
	}
	for _, value := range tList {
		for k, v := range value {
			if k != "USD" && v > 0 {
				finalAmount += v / currencyMap[k]
			} else {
				finalAmount += v
			}
		}
	}
	return &api.MerchantAccountRes{
		TotalAmount: fmt.Sprintf("%.4f", finalAmount),
	}, err
}

// 交易总金额
func (i *indexSrv) TotalTransactionAmount(ctx context.Context) (*api.TotalTransactionAmountRes, error) {
	type DbVo struct {
		MerchantNo string `json:"merchant_no"`
		Amount     string `json:"amount"`
		Currency   string `json:"currency"`
	}
	var (
		account         string
		collectList     []*DbVo
		iPayList        []*DbVo
		dPayList        []*DbVo
		exchangeList    []*DbVo
		rateObjList     []*model.IfcgateRate
		currencyRateMap = make(map[string]float64)
		tMap            = make(map[string]float64)
		finalAmount     float64
		err             error
	)
	account = ctx.Value("Account").(string)

	if err = global.GFDB.Schema("fx").Model("ifcgate_rate").
		Scan(&rateObjList); err != nil {
		logger.SugarLogger.Error(err)
		return nil, err
	}
	for _, value := range rateObjList {
		currencyRateMap[value.Currency] = value.Rate
	}

	// 收款
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_trade_order_mapping_flow").
		Fields("currency,amount,merchant_no").
		Where("account=? and status='02'", account).Scan(&collectList); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 国内付款
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_domestic_transfer_record").
		Fields("debit_currency as currency,debit_amount as amount,merchant_no").
		Where("account=? and status='1'", account).Scan(&dPayList); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 国际付款
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_internation_transfer_record").
		Fields("debit_currency as currency,debit_amount as amount,merchant_no").
		Where("account=? and status='SUCC'", account).Scan(&iPayList); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	// 换汇
	if err = global.GFDB.Ctx(ctx).Model("ifcgate_exchange_currency").
		Fields("sell_currency as currency,sell_amount as amount,merchant_no").
		Where("account=? and status='success'", account).Scan(&exchangeList); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}

	if len(collectList) > 0 {
		for _, value := range collectList {
			if _, ok := tMap[value.Currency]; !ok {
				tMap[value.Currency] = cast.ToFloat64(value.Amount)
			} else {
				tAmount := tMap[value.Currency]
				tMap[value.Currency] = cast.ToFloat64(value.Amount) + tAmount
			}
		}
	}
	if len(iPayList) > 0 {
		for _, value := range iPayList {
			if _, ok := tMap[value.Currency]; !ok {
				tMap[value.Currency] = cast.ToFloat64(value.Amount)
			} else {
				tAmount := tMap[value.Currency]
				tMap[value.Currency] = cast.ToFloat64(value.Amount) + tAmount
			}
		}
	}
	if len(dPayList) > 0 {
		for _, value := range dPayList {
			if _, ok := tMap[value.Currency]; !ok {
				tMap[value.Currency] = cast.ToFloat64(value.Amount)
			} else {
				tAmount := tMap[value.Currency]
				tMap[value.Currency] = cast.ToFloat64(value.Amount) + tAmount
			}
		}
	}
	if len(exchangeList) > 0 {
		for _, value := range exchangeList {
			if _, ok := tMap[value.Currency]; !ok {
				tMap[value.Currency] = cast.ToFloat64(value.Amount)
			} else {
				tAmount := tMap[value.Currency]
				tMap[value.Currency] = cast.ToFloat64(value.Amount) + tAmount
			}
		}
	}
	for key, value := range tMap {
		if key != "USD" && value > 0 {
			finalAmount += value / currencyRateMap[key]
		} else {
			finalAmount += value
		}
	}
	return &api.TotalTransactionAmountRes{
		TotalAmount: cast.ToString(finalAmount),
	}, err
}

// 分佣金额
func (i *indexSrv) TotalCommission(ctx context.Context) (*api.TotalCommissionRes, error) {
	type DbVo struct {
		Amount   float64 `json:"amount"`
		Currency string  `json:"currency"`
	}
	var (
		err             error
		account         string
		sqlStr          string
		withdrawList    []*model.IfcgateWithdrawRecord
		finalList       = make([]DbVo, 0)
		rateObjList     []*model.IfcgateRate
		currencyRateMap = make(map[string]float64)
		tMap            = make(map[string]float64, 0)
	)
	account = ctx.Value("Account").(string)

	dbList := make([]DbVo, 0)
	sqlStr = "select SUM(a.amount) as amount,a.currency FROM " +
		"(SELECT fixed_amount as amount,fixed_currency as currency FROM ifcgate_commission_record where account=? and budget_sign = 1 and account_type='agent' " +
		"UNION ALL SELECT commission_amount as amount,commission_currency as currency FROM ifcgate_commission_record where account=? and budget_sign = 1 and account_type='agent') " +
		"a where a.currency <>'' and a.amount > 0 GROUP BY a.currency"
	err = global.GFDB.Raw(sqlStr, account, account).Scan(&dbList)

	if err = global.GFDB.Ctx(ctx).Model("ifcgate_withdraw_record").
		Where("account=? and status='success'", account).Scan(&withdrawList); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}

	if err = global.GFDB.Schema("fx").Model("ifcgate_rate").
		Scan(&rateObjList); err != nil {
		logger.SugarLogger.Error(err)
		return nil, err
	}
	for _, value := range rateObjList {
		currencyRateMap[value.Currency] = value.Rate
	}

	currencyMap := make(map[string]float64)
	if len(withdrawList) > 0 {
		for _, value := range withdrawList {
			fAmount := cast.ToFloat64(value.Amount)
			if _, ok := currencyMap[value.Currency]; !ok {
				currencyMap[value.Currency] = fAmount
			} else {
				tAmount := currencyMap[value.Currency]
				currencyMap[value.Currency] = tAmount + value.Amount
			}
		}
	}

	for _, value := range dbList {
		if _, ok := currencyMap[value.Currency]; ok {
			finalList = append(finalList, DbVo{
				Amount:   value.Amount - currencyMap[value.Currency],
				Currency: value.Currency,
			})
		} else {
			finalList = append(finalList, DbVo{
				Amount:   value.Amount,
				Currency: value.Currency,
			})
		}
	}
	g.Dump(finalList)
	if len(finalList) > 0 {
		usdTAmount := 0.0000
		// 将算好的币种转换为美元
		for _, value := range finalList {
			if _, ok := tMap[value.Currency]; !ok {
				tMap[value.Currency] = value.Amount
			} else {
				tAmount := tMap[value.Currency]
				tMap[value.Currency] = value.Amount + tAmount
			}
		}
		for key, value := range tMap {
			if key != "USD" && value > 0 {
				usdTAmount += value / currencyRateMap[key]
			} else {
				usdTAmount += tMap[key]
			}
		}
		return &api.TotalCommissionRes{
			TotalAmount: fmt.Sprintf("%.4f", usdTAmount),
		}, err
	}
	return &api.TotalCommissionRes{}, err
}

func (i *indexSrv) GetPlacard(ctx context.Context) ([]*api.GetPlacardRes, error) {
	var (
		err  error
		list = make([]*api.GetPlacardRes, 0)
	)
	if err = global.GFDB.Ctx(ctx).Schema("boss").Model("fx_placard").
		Where("type='ifcgate_agent' and flag='1'").
		Order("created_at desc").Limit(1).
		Scan(&list); err != nil {
		logger.SugarLogger.Error(err.Error())
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	return list, err
}
